<template>
  <div id="qaOnline" style="position: relative; background-color: Gainsboro">
    <div id="html2canvas" ref="html2canvas" style="position: relative; height: 92vh">
      <SliderContainer v-on:content-resize="onWindowResize" v-bind:height="92 + 'vh'" v-bind:mark-type="markType">
        <template slot="left">
          <picture-list
            id="leftTopView"
            ref="pictureList_leftTopView"
            v-bind:height="46"
            v-bind:task-id="queryParams.taskId"
            v-bind:hide-tip="HideTip"
            v-bind:show-tip="ShowTip"
            v-bind:attribute-names="attributeNames"
            v-bind:color-names="colorNames"
            v-bind:sync_highlight_objects="sync_highlight_objects"
            v-bind:sync_clear_highlight_objects="sync_clear_highlight_objects"
            v-bind:set-position="setPosition"
            v-bind:elements-remark="elementsRemark"
            v-bind:handle-element-comments="handleElementComments"
            v-bind:change-cube-info="changeCubeInfo"
            v-bind:change-list="changeList"
          />
          <point-cloud
            id="leftBottomView"
            ref="pointCloud_leftBottomView"
            v-bind:height="46"
            v-bind:task-id="queryParams.taskId"
            v-bind:hide-tip="HideTip"
            v-bind:show-tip="ShowTip"
            v-bind:attribute-names="attributeNames"
            v-bind:render-type="renderType"
            v-bind:camera-position="cameraPosition"
            v-bind:high-light-cube-points="highLightCubePoints"
            v-bind:color-names="colorNames"
            v-bind:is-loading="isLoading"
            v-bind:loading="loading"
            v-bind:sync_highlight_objects="sync_highlight_objects"
            v-bind:sync_clear_highlight_objects="sync_clear_highlight_objects"
            v-bind:change-page="changePage"
            v-bind:set-position="setPosition"
            v-bind:elements-remark="elementsRemark"
            v-bind:handle-element-comments="handleElementComments"
            v-bind:plane-view-drawer="planeViewDrawer"
            v-bind:change-cube-info="changeCubeInfo"
          />
        </template>
        <template slot="right">
          <point-cloud
            id="rightTopView"
            ref="pointCloud_rightTopView"
            v-bind:height="46"
            v-bind:task-id="queryParams.taskId"
            v-bind:hide-tip="HideTip"
            v-bind:show-tip="ShowTip"
            v-bind:attribute-names="attributeNames"
            v-bind:render-type="renderType"
            v-bind:camera-position="cameraPosition"
            v-bind:high-light-cube-points="highLightCubePoints"
            v-bind:color-names="colorNames"
            v-bind:is-loading="isLoading"
            v-bind:loading="loading"
            v-bind:sync_highlight_objects="sync_highlight_objects"
            v-bind:sync_clear_highlight_objects="sync_clear_highlight_objects"
            v-bind:change-page="changePage"
            v-bind:set-position="setPosition"
            v-bind:elements-remark="elementsRemark"
            v-bind:handle-element-comments="handleElementComments"
            v-bind:plane-view-drawer="planeViewDrawer"
            v-bind:change-cube-info="changeCubeInfo"
          ></point-cloud>
          <picture-list
            id="rightBottomView"
            ref="pictureList_rightBottomView"
            v-bind:height="46"
            v-bind:task-id="queryParams.taskId"
            v-bind:hide-tip="HideTip"
            v-bind:show-tip="ShowTip"
            v-bind:attribute-names="attributeNames"
            v-bind:color-names="colorNames"
            v-bind:sync_highlight_objects="sync_highlight_objects"
            v-bind:sync_clear_highlight_objects="sync_clear_highlight_objects"
            v-bind:set-position="setPosition"
            v-bind:elements-remark="elementsRemark"
            v-bind:handle-element-comments="handleElementComments"
            v-bind:change-cube-info="changeCubeInfo"
            v-bind:change-list="changeList"
          />
        </template>
      </SliderContainer>
    </div>
    <div id="bottomDiv" class="bottom-div">
      <el-progress
        :percentage="cachePercentage"
        color="blue"
        v-show="cachePercentage > 0 && cachePercentage < 100"
        status="exception"
      ></el-progress>
      <el-row :gutter="20">
        <el-col :span="8" :xs="24">
          <el-form :inline="true">
            <el-form-item style="display: table-cell; width: 100%; text-align: left">
              <div class="filename">
                <span>{{ taskPath }}</span>
              </div>
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="8" :xs="24">
          <el-form align="center">
            <el-form-item style="">
              <el-button
                v-if="!playStarted"
                :disabled="cachePercentage != 100"
                type="primary"
                size="mini"
                @click="startPlay()"
                icon="el-icon-caret-right"
                circle
              />
              <el-button
                v-if="playStarted"
                type="primary"
                size="mini"
                @click="pausePlay()"
                icon="el-icon-video-pause"
                circle
              />
              <el-button
                type="primary"
                size="mini"
                :disabled="loading || currentIndex <= 0"
                @click="changePage(-1)"
                icon="el-icon-back"
                circle
              />
              <span
                >&nbsp;&nbsp;&nbsp;&nbsp;当前：({{ currentIndex + 1 }} /
                {{ fileList.length }})&nbsp;&nbsp;&nbsp;&nbsp;</span
              >
              <el-button
                type="primary"
                size="mini"
                :disabled="loading || currentIndex >= fileList.length - 1"
                @click="changePage(1)"
                icon="el-icon-right"
                circle
              />
              &nbsp;
              <el-select
                :value="currentIndex + 1"
                @change="
                  (value) => {
                    changePage(value - 1 - currentIndex)
                  }
                "
                style="width: 80px"
              >
                <el-option v-for="(item, index) in fileList" :key="item.fileId" :label="index + 1" :value="index + 1">
                </el-option>
              </el-select>
            </el-form-item>
          </el-form>
        </el-col>
        <el-col :span="8" :xs="24">
          <el-form :inline="true">
            <el-form-item style="display: table-cell; width: 100%; text-align: right">
              <div class="filename">
                <span v-if="fileList[currentIndex]">{{ fileList[currentIndex].fileId }}&nbsp;</span>
              </div>
            </el-form-item>
            <el-form-item style="display: table-cell">
              <!--el-popover
                placement="top-end"
                width="360"
                :visible-arrow="false"
                trigger="click">
                <div>
                  <div id="markAnnotationPanel" class="icon-list">
                    <div>
                      <p>标注列表：</p>
                    </div>
                    <div class="color-name" v-for="(dict, index) in markAnnotationList"
                         :key="index">
                      <span @click="markListClick(dict.key)">{{ dict.key + ": " + dict.value }}</span>
                    </div>
                  </div>
                </div>
                <el-button slot="reference" type="text" :disabled="isFullscreen" class="color-name-btn">
                  列表
                </el-button>
              </el-popover-->
            </el-form-item>
            <el-form-item style="display: table-cell">
              <el-popover
                placement="top-end"
                width="360"
                :visible-arrow="false"
                trigger="click"
                @show="showColorDialogVar = true"
                @hide="showColorDialogVar = false"
              >
                <div>
                  <div id="colorPanel" class="icon-list">
                    <div>
                      <p>属性色块：</p>
                    </div>
                    <div class="color-name" v-for="dict in colorNames" :key="dict.dictValue">
                      <svg :style="'height: 18px;width: 18px;'">
                        <rect width="18px" height="18px" :style="'fill:' + dict.dictLabel" />
                      </svg>
                      <span>{{ dict.dictValue }}</span>
                    </div>
                  </div>
                </div>
                <el-button slot="reference" type="text" :disabled="isFullscreen" class="color-name-btn">
                  色块
                  <i
                    style="transform: rotate(90deg)"
                    :class="showColorDialogVar ? 'el-icon-d-arrow-right' : 'el-icon-d-arrow-left'"
                  ></i>
                </el-button>
              </el-popover>
            </el-form-item>
          </el-form>
        </el-col>
      </el-row>
    </div>
    <el-dialog append-to-body :title="'目标信息'" :visible.sync="detailsDialogOpen" width="600px">
      <el-form :model="selectedObject" label-position="right" label-width="80px">
        <el-form-item v-for="attribute in selectedObject.attributes" :key="attribute.key" :label="attribute.key + ': '">
          <el-input v-model="attribute.value" maxlength="50" readonly />
        </el-form-item>
        <el-form-item label="错误类型" prop="errorType">
          <el-select
            v-model="selectedObject.errorType"
            @change="errorTypeSelectChanged"
            placeholder="请选择错误类型"
            clearable
            size="small"
          >
            <el-option
              v-for="dict in errorTypeOptions"
              :key="dict.dictValue"
              :label="dict.dictLabel"
              :value="dict.dictValue"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="'目标批注: '">
          <el-input
            id="detailRemarkInput"
            maxlength="80"
            placeholder="请在此输入针对改目标的批注"
            v-model="selectedObject.remark"
          />
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button
          type="primary"
          @click="
            handleElementComments(
              selectedObject.a1 ? selectedObject.a1 + '' : selectedObject.mMarkAnnotationId + '',
              selectedObject.remark,
              selectedObject
            )
          "
          >提 交</el-button
        >
        <el-button @click="detailsDialogOpen = false">取 消</el-button>
      </div>
    </el-dialog>

    <!-- 属性修改对话框 -->
    <el-dialog :title="'属性修改'" :visible.sync="attributesUpdateDialogOpen" width="480px" append-to-body>
      <el-form ref="form" :model="form" label-width="160px">
        <el-form-item label="类型" prop="name">
          <el-select v-model="form.name" placeholder="请选择类型">
            <el-option v-for="(value, key) in formOptions.name" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a1_2d_description" prop="a1" v-if="selectedObject.type == '2d'">
          <!--el-select v-if="selectedObject.type=='2d' && form.a1" v-model="form.a1" :placeholder="'请选择' + formOptions.a1_2d_description">
            <el-option
              v-for="(value, key) in formOptions.a1_2d"
              :key="key"
              :label="value"
              :value="key"
            />
          </el-select-->
          <el-input
            v-if="selectedObject.type == '2d' && form.a1"
            v-model="form.a1"
            :placeholder="'请选择' + formOptions.a1_2d_description"
            size="mini"
          />
        </el-form-item>
        <el-form-item :label="formOptions.a2_2d_description" prop="a2" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a2"
            v-model="form.a2"
            :placeholder="'请选择' + formOptions.a2_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a2_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a3_2d_description" prop="a3" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a3"
            v-model="form.a3"
            :placeholder="'请选择' + formOptions.a3_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a3_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a4_2d_description" prop="a4" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a4"
            v-model="form.a4"
            :placeholder="'请选择' + formOptions.a4_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a4_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a5_2d_description" prop="a5" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a5"
            v-model="form.a5"
            :placeholder="'请选择' + formOptions.a5_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a5_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a6_2d_description" prop="a6" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a6"
            v-model="form.a6"
            :placeholder="'请选择' + formOptions.a6_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a6_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a7_2d_description" prop="a7" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a7"
            v-model="form.a7"
            :placeholder="'请选择' + formOptions.a7_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a7_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a8_2d_description" prop="a8" v-if="selectedObject.type == '2d'">
          <el-select
            v-if="selectedObject.type == '2d' && form.a8"
            v-model="form.a8"
            :placeholder="'请选择' + formOptions.a8_2d_description"
          >
            <el-option v-for="(value, key) in formOptions.a8_2d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a1_3d_description" prop="a1" v-if="selectedObject.type == '3d'">
          <el-input
            v-if="selectedObject.type == '3d' && form.a1"
            v-model="form.a1"
            :placeholder="'请选择' + formOptions.a1_3d_description"
            size="mini"
          />
        </el-form-item>
        <el-form-item :label="formOptions.a2_3d_description" prop="a2" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a2"
            v-model="form.a2"
            :placeholder="'请选择' + formOptions.a2_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a2_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a3_3d_description" prop="a3" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a3"
            v-model="form.a3"
            :placeholder="'请选择' + formOptions.a3_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a3_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a4_3d_description" prop="a4" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a4"
            v-model="form.a4"
            :placeholder="'请选择' + formOptions.a4_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a4_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a5_3d_description" prop="a5" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a5"
            v-model="form.a5"
            :placeholder="'请选择' + formOptions.a5_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a5_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a6_3d_description" prop="a6" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a6"
            v-model="form.a6"
            :placeholder="'请选择' + formOptions.a6_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a6_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a7_3d_description" prop="a7" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a7"
            v-model="form.a7"
            :placeholder="'请选择' + formOptions.a7_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a7_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
        <el-form-item :label="formOptions.a8_3d_description" prop="a8" v-if="selectedObject.type == '3d'">
          <el-select
            v-if="selectedObject.type == '3d' && form.a8"
            v-model="form.a8"
            :placeholder="'请选择' + formOptions.a8_3d_description"
          >
            <el-option v-for="(value, key) in formOptions.a8_3d" :key="key" :label="value" :value="key" />
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitUpdateForm">确 定</el-button>
        <el-button @click="cancelUpdateForm">取 消</el-button>
      </div>
    </el-dialog>

    <div id="focus_toolTip" class="special_focus_toolTip" v-html="toolTopbody" />
    <RemarkList
      ref="remarkList"
      :task-id="queryParams.taskId"
      :set-position="setPosition"
      :delete-remark="deleteRemark"
      :update-remark="updateRemark"
    />
  </div>
</template>
<script>
import $ from 'jquery'
import {
  getMarkAnnotations,
  pointsCloudDetails,
  imageFile,
  pcdBlob,
  updateAnnotation,
  updateAnnotationAttributes,
  deleteAnnotation,
} from '@/api/mark/onlineCheck'
import { listResult, updateResult } from '@/api/mark/qaresult'
import { getQaTask } from '@/api/mark/qaTask'
import screenfull from 'screenfull'
import { checkRole } from '@/utils/permission'
import PictureList from './components/PictureList'
import PointCloud from './components/PointCloud'
import SliderContainer from './components/SliderContainer'
import RemarkList from './components/RemarkList'
import { listRemarkBall, delRemarkBall, addRemarkBall } from '@/api/mark/remarkBall'
import { Dictionary } from '@/utils/dictionary'
import html2canvas from 'html2canvas'
import * as Whammy from './whammy.js'

export default {
  name: 'FuseEditor',
  components: {
    SliderContainer,
    PictureList,
    PointCloud,
    RemarkList,
  },
  computed: {
    markAnnotations() {
      return this.$store.state.markData.markAnnotations
    },
  },
  // watch: {
  //   '$route' (to, from) {
  //     if(this.$route.query.index) {
  //       this.changePage(parseInt(this.$route.query.index) - this.currentIndex - 1);
  //     }
  //   }
  // },
  data() {
    return {
      playCachePromise: undefined,
      playing: false,
      playStarted: false,
      taskPath: '',
      seconds: 0,
      interval: undefined,
      playIndex: 0,
      scaleFactor: undefined,
      showAttributesText: false,
      animationFrameId: undefined,
      mouseDown: false,
      renderEnabled: false,
      pointTextFontSize: 48,
      detailsDialogOpen: false,
      showColorDialogVar: false,
      isFullscreen: false,
      queryParams: {
        taskId: undefined,
        mQaResultId: undefined,
      },
      selectedObject: {
        a1: '',
        remark: '',
        attributes: [],
        type: '',
        imageIndex: '',
        errorType: '',
        mPoint: {
          x: -1,
          y: -1,
          z: -1,
        },
        elementInstance: null,
        position: null,
      },
      cubeInfo: { width: '', height: '', length: '' },
      errorTypeOptions: [],
      currentSelection: {},
      colorNames: {},
      attributeNames: {},
      imgCount: 0,
      markType: 0,
      tipContent: '',
      colorBody: '',
      toolTopbody: '',
      remarkMap: new Map(), // 批注图标
      loading: false,

      currentStatus: '',
      currentIndex: -1,
      fileList: {},
      remark: '',
      elementsRemark: {},
      renderType: 'benzLabel',
      highLightCubePoints: 'false',
      cameraPosition: null,
      selectedObjectA1: null,
      attrsViewDrawer: false,
      planeViewDrawer: false,
      changeList: new Dictionary(),
      attributesUpdateDialogOpen: false,
      // 属性修改表单参数
      form: {
        mMarkAnnotationId: undefined,
        name: undefined,
        a1: undefined,
        a2: undefined,
        a3: undefined,
        a4: undefined,
        a5: undefined,
        a6: undefined,
        a7: undefined,
        a8: undefined,
      },
      formOptions: {},
      remarkListVisable: false,
      cacheStatus: {
        taskId: null,
        cacheIndex: 0,
      },
      cachePercentage: 0,
      lastPlayTime: null,
      hideOther: false,
      encoder: null,
    }
  },
  methods: {
    checkrole(role) {
      return checkRole(role)
    },
    // 批注列表点击后图片和点云矩形缩放定位
    setPosition(a1, mQaResultId, remark, type, imageIndex, errorType, point, position) {
      if (!a1 && !position) return
      this.selectedObjectA1 = a1
      // if (this.fileList && mQaResultId && this.fileList[this.currentIndex].mQaResultId != mQaResultId) {
      //   for (let i = 0; i < this.fileList.length; i ++) {
      //     if (this.fileList[i].mQaResultId == mQaResultId) {
      //       this.changePage(i - this.currentIndex);
      //     }
      //   }
      // }
      if (this.$route.query.index) {
        this.changePage(parseInt(this.$route.query.index) - this.currentIndex - 1)
      }
      if (this.markType === 10) return
      this.selectedObject.a1 = a1
      this.selectedObject.remark = remark
      this.selectedObject.type = type
      this.selectedObject.imageIndex = imageIndex
      this.selectedObject.errorType = errorType
      this.selectedObject.position = position
      if (type == '2d') {
        this.selectedObject.attributes = this.$refs.pictureList_leftTopView.getSelectedObjectAttributes(a1)
        this.selectedObject.attributes = this.$refs.pictureList_rightBottomView.getSelectedObjectAttributes(a1)
      } else if (type == '3d') {
        this.selectedObject.attributes = this.$refs.pointCloud_rightTopView.getSelectedObjectAttributes(a1)
        this.selectedObject.attributes = this.$refs.pointCloud_leftBottomView.getSelectedObjectAttributes(a1)
      }
      this.sync_highlight_objects('', this.selectedObject)
    },
    // 批注列表删除批注后更新图片和点云显示的批注图标
    deleteRemark(a1, type, elementsRemarkKey) {
      // 这里处理重新打开批注弹框时的remark input值
      if (this.selectedObject.a1 == a1 && type && this.selectedObject.type == type) {
        this.selectedObject.remark = ''
      }
      // 删除 this.elementsRemark 对应的记录
      let item = this.remarkMap.get(elementsRemarkKey)
      if (item && type == '2d') {
        item.remove()
        item.missObject && item.missObject.remove()
      }
      this.elementsRemark[elementsRemarkKey] = null
      this.elementsRemark['ball-' + elementsRemarkKey] = null
      this.remarkMap.delete(elementsRemarkKey)
      this.$refs.pointCloud_rightTopView.reRender()
      this.$refs.pointCloud_leftBottomView.reRender()
      this.$refs.pictureList_leftTopView.reRender()
      this.$refs.pictureList_rightBottomView.reRender()
    },
    // 批注列表更新批注后更新缓存批注数据
    updateRemark(a1, type, elementsRemarkKey, remark) {
      // 这里处理重新打开批注弹框时的remark input值
      if (this.selectedObject.a1 == a1 && type && this.selectedObject.type == type) {
        this.selectedObject.remark = remark
      }
      this.elementsRemark[elementsRemarkKey] = remark
      if (this.elementsRemark['ball-' + elementsRemarkKey])
        this.elementsRemark['ball-' + elementsRemarkKey].remark = remark
      this.$refs.pointCloud_rightTopView.reRender()
      this.$refs.pointCloud_leftBottomView.reRender()
      this.$refs.pictureList_leftTopView.reRender()
      this.$refs.pictureList_rightBottomView.reRender()
    },
    errorTypeSelectChanged(value) {
      for (let i = 0; i < this.errorTypeOptions.length; i++) {
        if (this.errorTypeOptions[i].dictValue === value) {
          this.selectedObject.remark = this.errorTypeOptions[i].dictLabel
          return
        }
      }
      this.selectedObject.remark = ''
    },
    // 更新批注信息（新增或删除批注）
    handleElementComments(id, remark, selectedObject) {
      this.selectedObject = selectedObject
      let remarkBall = {
        taskId: this.fileList[this.currentIndex].taskId,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
        fileName: this.fileList[this.currentIndex].fileId,
        trackId: id,
        mType:
          this.selectedObject.type + (this.selectedObject.type == '2d' ? '-' + this.selectedObject.imageIndex : ''),
        errorType: this.selectedObject.errorType,
        remark: remark,
        x: this.selectedObject.mPoint.x,
        y: this.selectedObject.mPoint.y,
        z: this.selectedObject.mPoint.z,
      }
      if (remark && remark !== '') {
        if (id) {
          addRemarkBall(remarkBall).then((response) => {
            if (response.code === 200) {
              if (this.selectedObject.elementInstance)
                this.selectedObject.elementInstance.markRemarkId = response.markRemarkId
              if (this.markType === 10) {
                this.removeCache(this.form.mQaResultId)
                this.changePage(0)
              }
              this.msgSuccess('更新成功')
            } else {
              this.msgError(response.msg)
            }
          })
        } else {
          this.msgInfo('未选中目标。')
        }
      } else {
        delRemarkBall(this.selectedObject.elementInstance.markRemarkId).then((response) => {
          if (response.code === 200) {
            this.msgSuccess('删除成功')
          } else {
            this.msgError(response.msg)
          }
        })
      }
      this.detailsDialogOpen = false
      if (id == null || id == '' || id == undefined) return
      if (!id.startsWith('lou-') && parseInt(this.markType) !== 10) {
        id =
          id +
          '-' +
          this.selectedObject.type +
          (this.selectedObject.imageIndex != '' ? '-' + this.selectedObject.imageIndex : '')
        this.elementsRemark[id] = remark
        this.elementsRemark['ball-' + this.selectedObject.a1 + '-' + remarkBall.mType] = this.selectedObject.errorType
        this.sync_highlight_objects('', this.selectedObject)
      }
    },
    // 验收提交
    handleComments(ret) {
      this.fileList[this.currentIndex].mQaResult = ret
      this.fileList[this.currentIndex].remark = this.remark
      let data = {
        taskId: this.fileList[this.currentIndex].taskId,
        fileId: this.fileList[this.currentIndex].fileId,
        markResultId: this.fileList[this.currentIndex].markResultId,
        markType: this.fileList[this.currentIndex].markType,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
        mQaResult: this.fileList[this.currentIndex].mQaResult,
        createBy: this.fileList[this.currentIndex].createBy,
        createTime: this.fileList[this.currentIndex].createTime,
        updateBy: this.fileList[this.currentIndex].updateBy,
        updateTime: this.fileList[this.currentIndex].updateTime,
        remark: this.fileList[this.currentIndex].remark,
      }
      updateResult(data).then((response) => {
        if (response.code === 200) {
          if (ret == '') {
            this.msgSuccess('批注更新成功。')
          } else if (this.currentIndex < this.fileList.length - 1) {
            this.changePage(1)
            this.msgSuccess('标注结果' + ret + '，开始载入下一张。')
          } else {
            this.msgSuccess('标注结果' + ret + '，已到达最后一张。')
          }
        } else {
          this.msgError(response.msg)
        }
      })
    },
    // 翻页函数，上一页、下一页翻页，页码跳转、选中批注后跳转页码
    changePage(num, playModel = false) {
      if (this.changeList.count() > 0) {
        this.$confirm('当前页面存在未保存的数据，是否忽略所做的修改?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'email',
        })
          .then(() => {
            this.changePage1(num, playModel)
          })
          .catch(function () {})
      } else {
        this.changePage1(num, playModel)
      }
    },
    changePage1(num, playModel = false) {
      this.changeList.clear()
      console.debug('start change page.')
      cancelAnimationFrame(this.animationFrameId)

      if (this.currentIndex + num < 0 || this.currentIndex + num >= this.fileList.length) return
      this.currentIndex += num
      this.remark = this.fileList[this.currentIndex].remark
      let query = {
        taskId: this.queryParams.taskId,
        mQaResultId: this.fileList[this.currentIndex].mQaResultId,
      }

      this.$router.replace({ path: '/mark/RadarView', query: query })

      this.currentStatus = this.fileList[this.currentIndex].mQaResult
        ? this.fileList[this.currentIndex].mQaResult
        : '待验收'
      this.$store.dispatch('mqaResultCurrentIndexCached', this.currentIndex)

      if (parseInt(this.markType) !== 10) {
        this.$refs.pointCloud_rightTopView.getPointsCloud(
          this.fileList,
          this.currentIndex,
          this.fileList[this.currentIndex].mQaResultId,
          playModel,
          this.showAttributesText,
          'Bumper'
        )
        this.$refs.pointCloud_leftBottomView.getPointsCloud(
          this.fileList,
          this.currentIndex,
          this.fileList[this.currentIndex].mQaResultId,
          playModel,
          this.showAttributesText
        )
      }
      if (this.imgCount > 0) {
        this.$refs.pictureList_leftTopView.loadDrawing(
          this.currentIndex,
          this.fileList[this.currentIndex].mQaResultId,
          this.showAttributesText
        )
        this.$refs.pictureList_rightBottomView.loadDrawing(
          this.currentIndex,
          this.fileList[this.currentIndex].mQaResultId,
          this.showAttributesText
        )
      }
    },
    cacheFile(qaResultId) {
      const readValue = this.$store.state.markData.markAnnotations['MA:' + qaResultId]
      if (!readValue) {
        pointsCloudDetails(qaResultId).then((res) => {
          if (res.fileType === 'pcd') {
            this.$store.state.markData.markAnnotations.set('MA:' + qaResultId, res.annotation)
          }
        })
      } else {
        console.debug(qaResultId, ' exist.')
      }
    },
    removeCache(qaResultId) {
      this.markAnnotations.delete('MA:' + qaResultId + '')
      if (this.imgCount === 1) {
        this.markAnnotations.delete('MA:' + qaResultId + ':img')
      } else if (this.imgCount !== 0) {
        for (let j = 0; j < this.imgCount; j++) {
          this.markAnnotations.delete('MA:' + qaResultId + ':img' + (j + 1))
        }
      }
    },
    // 缓存点云和标注数据到localStorage
    saveToCacheDB(_key, _value) {
      this.$setItem(_key, _value, function () {})
    },
    markListClick(trackId) {
      this.selectedObject.a1 = trackId
      this.sync_highlight_objects('', this.selectedObject)
    },
    // 页面全屏函数
    threejsFullScreen() {
      this.isFullscreen = !this.isFullscreen
      if (this.isFullscreen) {
        try {
          screenfull.request(document.getElementById('qaOnline'))
        } catch (err) {}
      } else {
        try {
          screenfull.toggle()
        } catch (err) {}
      }
    },
    // 返回到质检结果记录列表页面
    returnFileList(e) {
      // history.back();
      history.pushState(null, null, document.URL)
      if (e) e.preventDefault()
      this.$router.replace({ path: '/mark/result', query: { taskId: this.queryParams.taskId } })
      for (let i = 0; i < this.$store.state.tagsView.visitedViews.length; i++) {
        if (this.$store.state.tagsView.visitedViews[i].name === 'Editor2d') {
          this.$store.dispatch('tagsView/delView', this.$store.state.tagsView.visitedViews[i])
        }
      }
    },
    // 快捷键监听函数
    keyDownHandler(e) {
      if (
        $(document.activeElement).hasClass('skip-shortcuts') ||
        $(document.activeElement).parent().hasClass('skip-shortcuts')
      ) {
        return
      }
      // enter
      if (document.activeElement.id == 'remarkInput') {
        if (e.keyCode == 13 || e.keyCode == 32) {
          e.preventDefault()
        }
        return
      }
      if (document.activeElement.id == 'detailRemarkInput') {
        if (e.keyCode == 13 || e.keyCode == 32) {
          e.preventDefault()
          if (e.keyCode == 13 && this.selectedObject && this.selectedObject.remark) {
            this.handleElementComments(
              this.selectedObject.a1 ? this.selectedObject.a1 + '' : this.selectedObject.mMarkAnnotationId + '',
              this.selectedObject.remark,
              this.selectedObject
            )
          }
        }
        return
      }
      if (document.activeElement.id == 'trackID') {
        if (e.keyCode == 13 && this.selectedObject && this.selectedObject.a1) {
          this.sync_highlight_objects('', this.selectedObject)
        }
      }
      if (e.keyCode == 13) {
        e.preventDefault()
        return
      }
      if (e.altKey && e.ctrlKey) {
        this.showAttributesText = !this.showAttributesText
        this.$refs.pictureList_leftTopView.showAttributesText2D(this.showAttributesText)
        this.$refs.pictureList_rightBottomView.showAttributesText2D(this.showAttributesText)
        this.$refs.pointCloud_rightTopView.showAttributesText2D(this.showAttributesText)
        this.$refs.pointCloud_leftBottomView.showAttributesText2D(this.showAttributesText)
        e.preventDefault()
        return
      }
      if (e.ctrlKey && e.shiftKey) {
        if (this.selectedObject && this.selectedObject.a1) {
          this.hideOther = !this.hideOther
        } else {
          this.hideOther = false
        }
        this.$refs.pictureList_leftTopView.highlight_objects(undefined, this.selectedObject, false, this.hideOther)
        this.$refs.pictureList_rightBottomView.highlight_objects(undefined, this.selectedObject, false, this.hideOther)
        if (this.markType !== 10) {
          this.$refs.pointCloud_rightTopView.highlight_objects(undefined, this.selectedObject, false, this.hideOther)
          this.$refs.pointCloud_leftBottomView.highlight_objects(undefined, this.selectedObject, false, this.hideOther)
        }
      }
      // e
      if (e.keyCode == 69) {
        e.preventDefault()
        if (this.selectedObject) {
          this.HideTip()
          this.detailsDialogOpen = true
          let detailRemarkInput = document.getElementById('detailRemarkInput')
          if (detailRemarkInput) detailRemarkInput.focus()
        }
      }
      // t
      else if (e.keyCode == 84) {
        e.preventDefault()
        let remarkInput = document.getElementById('remarkInput')
        remarkInput.focus()
      }
      // q
      else if (e.keyCode == 81) {
        history.back()
      }
      // f
      else if (e.keyCode == 70) {
        if (!this.isFullscreen) {
          this.threejsFullScreen()
        }
      }
      // a
      else if (e.keyCode == 65) {
        if (this.currentIndex >= 1 && this.loading !== true) {
          this.changePage(-1)
        }
      }
      // d
      else if (e.keyCode == 68) {
        if (this.currentIndex < this.fileList.length - 1 && this.loading !== true) {
          this.changePage(1)
        }
      }
      // s
      else if (e.keyCode == 83 && this.loading !== true) {
        this.handleComments('通过')
      }
      // w
      else if (e.keyCode == 87 && this.loading !== true) {
        this.handleComments('驳回')
      }
      // r
      else if (e.keyCode == 82 && this.loading !== true) {
        this.handleComments('挂起')
      }
      // ALT + x
      else if (e.keyCode == 88 && e.altKey) {
        this.form.mMarkAnnotationId = this.selectedObject.mMarkAnnotationId
        this.form.mQaResultId = this.fileList[this.currentIndex].mQaResultId
        this.form.name = this.selectedObject.name
        this.form.a1 = this.selectedObject.a1 && this.selectedObject.a1 !== 'null' ? this.selectedObject.a1 : null
        this.form.a2 =
          this.selectedObject.a2 && this.selectedObject.a2 !== 'null' && !this.selectedObject.a2.startsWith('长：')
            ? this.selectedObject.a2
            : null
        this.form.a3 =
          this.selectedObject.a3 && this.selectedObject.a3 !== 'null' && !this.selectedObject.a3.startsWith('长：')
            ? this.selectedObject.a3
            : null
        this.form.a4 =
          this.selectedObject.a4 && this.selectedObject.a4 !== 'null' && !this.selectedObject.a4.startsWith('长：')
            ? this.selectedObject.a4
            : null
        this.form.a5 =
          this.selectedObject.a5 && this.selectedObject.a5 !== 'null' && !this.selectedObject.a5.startsWith('长：')
            ? this.selectedObject.a5
            : null
        this.form.a6 =
          this.selectedObject.a6 && this.selectedObject.a6 !== 'null' && !this.selectedObject.a6.startsWith('长：')
            ? this.selectedObject.a6
            : null
        this.form.a7 =
          this.selectedObject.a7 && this.selectedObject.a7 !== 'null' && !this.selectedObject.a7.startsWith('长：')
            ? this.selectedObject.a7
            : null
        this.form.a8 =
          this.selectedObject.a8 && this.selectedObject.a8 !== 'null' && !this.selectedObject.a8.startsWith('长：')
            ? this.selectedObject.a8
            : null
        this.attributesUpdateDialogOpen = true
      }
    },
    isLoading(loading) {
      this.loading = loading
    },
    // 查询验收任务信息，包含属性类型、颜色类型等基础字典数据
    async qaTaskQuery() {
      let splitLine
      await getQaTask(this.queryParams.taskId).then(async (response) => {
        this.taskPath = response.data.taskName
        if (response.data.taskName.startsWith('0.')) {
          splitLine = parseFloat(response.data.taskName)
        }
        if (response.data && response.data.parentId !== 0) {
          await getQaTask(response.data.parentId).then(async (response) => {
            if (response.data) {
              this.taskPath = response.data.taskName + ' -> ' + this.taskPath
              if (response.data.taskName.startsWith('0.')) {
                splitLine = parseFloat(response.data.taskName)
              }
              if (response.data.parentId !== '0') {
                await getQaTask(response.data.parentId).then(async (response) => {
                  if (response.data) {
                    this.taskPath = response.data.taskName + ' -> ' + this.taskPath
                    if (response.data.taskName.startsWith('0.')) {
                      splitLine = parseFloat(response.data.taskName)
                    }
                  }
                })
              }
            }
          })
        }
      })
      this.$getItem('QaTask:' + this.queryParams.taskId, (err, readValue) => {
        if (readValue) {
          this.$getItem(readValue.data.markAttributes, (err, attributes) => {
            if (attributes) {
              this.attributeNames = attributes
              this.formOptionsInit()
              if (splitLine) {
                let _data = {
                  dictValue: 'splitLine',
                  dictLabel: splitLine,
                }
                this.attributeNames.push(_data)
              }
              this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
              this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
            } else {
              this.getDicts(readValue.data.markAttributes).then((res1) => {
                this.attributeNames = res1.data
                this.formOptionsInit()
                this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
                this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
              })
            }
          })
          this.$getItem(readValue.data.markAttributes + '_colors', (err, attributesColors) => {
            if (attributesColors) {
              this.colorNames = attributesColors
            } else {
              this.getDicts(readValue.data.markAttributes + '_colors').then((res1) => {
                this.colorNames = res1.data
              })
            }
          })
          this.markType = parseInt(readValue.data.markType)
          this.imgCount = this.markType == 9 ? 0 : this.markType == 10 ? 1 : this.markType
          this.showColorDialogVar = this.imgCount <= 1
          this.$refs.pictureList_leftTopView.initPaperToolPosition(this.imgCount, this.markType)
          this.$refs.pictureList_rightBottomView.initPaperToolPosition(this.imgCount, this.markType)
          this.getListResult()
        } else {
          getQaTask(this.queryParams.taskId).then((response) => {
            this.getDicts(response.data.markAttributes).then((res1) => {
              this.attributeNames = res1.data
              this.formOptionsInit()
              if (splitLine) {
                let _data = {
                  dictValue: 'splitLine',
                  dictLabel: splitLine,
                }
                this.attributeNames.push(_data)
              }
              this.cameraPosition = this.selectDictLabel(this.attributeNames, 'cameraPosition')
              this.highLightCubePoints = this.selectDictLabel(this.attributeNames, 'highLightCubePoints')
            })
            this.getDicts(response.data.markAttributes + '_colors').then((res1) => {
              this.colorNames = res1.data
            })
            this.markType = parseInt(response.data.markType)
            this.imgCount = this.markType == 9 ? 0 : this.markType == 10 ? 1 : this.markType
            this.showColorDialogVar = this.imgCount <= 1
            this.$refs.pictureList_leftTopView.initPaperToolPosition(this.imgCount)
            this.$refs.pictureList_rightBottomView.initPaperToolPosition(this.imgCount)
            this.getListResult()
          })
        }
      })
    },
    formOptionsInit() {
      try {
        this.formOptions.name = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName')).values
        let a1_2d = this.selectDictLabel(this.attributeNames, 'a1_2d')
        if (a1_2d) {
          this.formOptions.a1_2d = JSON.parse(a1_2d).values
          this.formOptions.a1_2d_description = JSON.parse(a1_2d).typeDesc
        }
        let a2_2d = this.selectDictLabel(this.attributeNames, 'a2_2d')
        if (a2_2d) {
          this.formOptions.a2_2d = JSON.parse(a2_2d).values
          this.formOptions.a2_2d_description = JSON.parse(a2_2d).typeDesc
        }
        let a3_2d = this.selectDictLabel(this.attributeNames, 'a3_2d')
        if (a3_2d) {
          this.formOptions.a3_2d = JSON.parse(a3_2d).values
          this.formOptions.a3_2d_description = JSON.parse(a3_2d).typeDesc
        }
        let a4_2d = this.selectDictLabel(this.attributeNames, 'a4_2d')
        if (a4_2d) {
          this.formOptions.a4_2d = JSON.parse(a4_2d).values
          this.formOptions.a4_2d_description = JSON.parse(a4_2d).typeDesc
        }
        let a5_2d = this.selectDictLabel(this.attributeNames, 'a5_2d')
        if (a5_2d) {
          this.formOptions.a5_2d = JSON.parse(a5_2d).values
          this.formOptions.a5_2d_description = JSON.parse(a5_2d).typeDesc
        }
        let a6_2d = this.selectDictLabel(this.attributeNames, 'a6_2d')
        if (a6_2d) {
          this.formOptions.a6_2d = JSON.parse(a6_2d).values
          this.formOptions.a6_2d_description = JSON.parse(a6_2d).typeDesc
        }
        let a7_2d = this.selectDictLabel(this.attributeNames, 'a7_2d')
        if (a7_2d) {
          this.formOptions.a7_2d = JSON.parse(a7_2d).values
          this.formOptions.a7_2d_description = JSON.parse(a7_2d).typeDesc
        }
        let a8_2d = this.selectDictLabel(this.attributeNames, 'a8_2d')
        if (a8_2d) {
          this.formOptions.a8_2d = JSON.parse(a8_2d).values
          this.formOptions.a8_2d_description = JSON.parse(a8_2d).typeDesc
        }
        let a1_3d = this.selectDictLabel(this.attributeNames, 'a1_3d')
        if (a1_3d) {
          this.formOptions.a1_3d = JSON.parse(a1_3d).values
          this.formOptions.a1_3d_description = JSON.parse(a1_3d).typeDesc
        }
        let a2_3d = this.selectDictLabel(this.attributeNames, 'a2_3d')
        if (a2_3d) {
          this.formOptions.a2_3d = JSON.parse(a2_3d).values
          this.formOptions.a2_3d_description = JSON.parse(a2_3d).typeDesc
        }
        let a3_3d = this.selectDictLabel(this.attributeNames, 'a3_3d')
        if (a3_3d) {
          this.formOptions.a3_3d = JSON.parse(a3_3d).values
          this.formOptions.a3_3d_description = JSON.parse(a3_3d).typeDesc
        }
        let a4_3d = this.selectDictLabel(this.attributeNames, 'a4_3d')
        if (a4_3d) {
          this.formOptions.a4_3d = JSON.parse(a4_3d).values
          this.formOptions.a4_3d_description = JSON.parse(a4_3d).typeDesc
        }
        let a5_3d = this.selectDictLabel(this.attributeNames, 'a5_3d')
        if (a5_3d) {
          this.formOptions.a5_3d = JSON.parse(a5_3d).values
          this.formOptions.a5_3d_description = JSON.parse(a5_3d).typeDesc
        }
        let a6_3d = this.selectDictLabel(this.attributeNames, 'a6_3d')
        if (a6_3d) {
          this.formOptions.a6_3d = JSON.parse(a6_3d).values
          this.formOptions.a6_3d_description = JSON.parse(a6_3d).typeDesc
        }
        let a7_3d = this.selectDictLabel(this.attributeNames, 'a7_3d')
        if (a7_3d) {
          this.formOptions.a7_3d = JSON.parse(a7_3d).values
          this.formOptions.a7_3d_description = JSON.parse(a7_3d).typeDesc
        }
        let a8_3d = this.selectDictLabel(this.attributeNames, 'a8_3d')
        if (a8_3d) {
          this.formOptions.a8_3d = JSON.parse(a8_3d).values
          this.formOptions.a8_3d_description = JSON.parse(a8_3d).typeDesc
        }
      } catch (e) {
        console.log(e)
      }
    },
    // 获取质检结果记录数据列表，并调用图片列表和点云视图的渲染函数进行页面渲染
    getListResult() {
      listResult(this.queryParams).then((response) => {
        this.cachePercentage = 0
        this.fileList = response.rows
        for (let i = 0; i < response.total; i++) {
          if (this.queryParams.mQaResultId == null || this.queryParams.mQaResultId == this.fileList[i].mQaResultId) {
            this.queryParams.mQaResultId = this.fileList[i].mQaResultId
            this.currentIndex = i
            this.currentStatus = this.fileList[this.currentIndex].mQaResult
              ? this.fileList[this.currentIndex].mQaResult
              : '待验收'
            this.remark = this.fileList[this.currentIndex].remark
            this.$store.dispatch('mqaResultCurrentIndexCached', this.currentIndex)
            if (parseInt(this.markType) !== 10) {
              this.$refs.pointCloud_rightTopView.init()
              this.$refs.pointCloud_rightTopView.getPointsCloud(
                this.fileList,
                this.currentIndex,
                this.fileList[i].mQaResultId,
                false,
                this.showAttributesText,
                'Bumper'
              )
              this.$refs.pointCloud_leftBottomView.init()
              this.$refs.pointCloud_leftBottomView.getPointsCloud(
                this.fileList,
                this.currentIndex,
                this.fileList[i].mQaResultId,
                false,
                this.showAttributesText
              )
            }
            if (this.imgCount > 0) {
              if (this.imgCount == 1 || parseInt(this.markType) == 10) this.imgIndex = 0
              else this.imgIndex = 1
              this.$refs.pictureList_leftTopView.loadDrawing(this.currentIndex, this.fileList[i].mQaResultId)
              this.$refs.pictureList_rightBottomView.loadDrawing(this.currentIndex, this.fileList[i].mQaResultId)
            }
            break
          }
        }

        let getAllKeysPromise = new Promise((resolve, reject) => {
          this.$getAllKeys((allkeys) => {
            resolve(allkeys)
          })
        })

        getAllKeysPromise.then((ret) => {
          this.pcdCache(this.$route.query.taskId, ret)
        })

        this.removeAnnotationCache('MA:')
        this.removeAnnotationCache('RM:')
        try {
          getMarkAnnotations(this.$route.query.taskId).then((res) => {
            this.$store.dispatch('markAnnotationsCached', res.annotations)
          })
          listRemarkBall({ taskId: this.$route.query.taskId }).then((res) => {
            this.$store.dispatch('remarkListCached', res.rows)
          })
        } catch (e) {
          console.debug('getMarkAnnotations Exception: ' + e)
        }
        this.jumpToBottom()
      })
    },
    async pcdCache(taskId, allkeys) {
      // if(this.cacheStatus && this.cacheStatus.taskId == taskId) return;
      this.cacheStatus.taskId = taskId
      this.cacheStatus.cacheIndex = 0

      while (this.cacheStatus && this.cacheStatus.cacheIndex < this.fileList.length) {
        let resultId = this.fileList[this.cacheStatus.cacheIndex].mQaResultId
        this.cachePercentage = parseInt((this.cacheStatus.cacheIndex * 100) / this.fileList.length)

        if (allkeys.indexOf(resultId) != -1) {
          this.cacheStatus.cacheIndex++
          continue
        }

        await pcdBlob(resultId).then((response) => {
          let blob = new Blob([response.data], { type: 'application/octet-stream' })
          let _data = {
            blob: blob,
            file_name: resultId,
          }
          this.$save(_data)
          if (this.cacheStatus) {
            console.info(
              '[' + /\d\d\:\d\d\:\d\d/.exec(new Date())[0] + ']',
              'save ' + this.fileList[this.cacheStatus.cacheIndex].fileId
            )
            this.cacheStatus.cacheIndex++
          }
        })

        try {
          if (this.imgCount === 1) {
            await imageFile(resultId, 0).then((response) => {
              let imageSrc = response.imageSrc
              let annotation = response.annotation
              let _data = {
                blob: imageSrc,
                file_name: resultId + ':img',
              }
              this.$save(_data)
              this.markAnnotations.set('MA:' + resultId + ':img', annotation)
            })
          } else {
            for (let j = 0; j < this.imgCount; j++) {
              await imageFile(resultId, j + 1).then((response) => {
                let imageSrc = response.imageSrc
                let annotation = response.annotation
                let _data = {
                  blob: imageSrc,
                  file_name: resultId + ':img' + (j + 1),
                }
                this.$save(_data)
                this.markAnnotations.set('MA:' + resultId + ':img' + (j + 1), annotation)
              })
            }
          }
        } catch (e) {
          console.debug(e)
        }
      }
      this.cachePercentage = parseInt((this.cacheStatus.cacheIndex * 100) / this.fileList.length)
    },
    // 图片列表和点云视图的公共定位缩放函数
    sync_highlight_objects(eventSource, selectedObject, cubeInfo, isZoom = true) {
      this.selectedObject = selectedObject
      this.cubeInfo = cubeInfo
      this.hideOther = false
      this.$refs.pictureList_leftTopView.highlight_objects(eventSource, selectedObject, isZoom, this.hideOther)
      this.$refs.pictureList_rightBottomView.highlight_objects(eventSource, selectedObject, isZoom, this.hideOther)
      if (this.markType !== 10) {
        this.$refs.pointCloud_rightTopView.highlight_objects(eventSource, selectedObject, isZoom, this.hideOther)
        this.$refs.pointCloud_leftBottomView.highlight_objects(eventSource, selectedObject, isZoom, this.hideOther)
      }
    },
    sync_clear_highlight_objects(selectedObject) {
      this.selectedObject = selectedObject
      this.$refs.pictureList_leftTopView.clear_highlight_objects()
      this.$refs.pictureList_rightBottomView.clear_highlight_objects()
      this.$refs.pointCloud_rightTopView.clear_highlight_objects()
      this.$refs.pointCloud_leftBottomView.clear_highlight_objects()
    },
    // 更新右侧属性信息
    changeCubeInfo(cubeInfo) {
      this.cubeInfo = cubeInfo
    },
    jumpToBottom() {
      document.querySelector('#bottomDiv').scrollIntoView(true)
    },
    HideTip() {
      $('#focus_toolTip').css('display', 'none')
    },
    // 显示标注矩形的属性弹框信息
    ShowTip(message, x, y, tipType = 'tip') {
      if (this.detailsDialogOpen) return
      // if(this.markType === 10) return;
      let focusTooltip = $('#focus_toolTip')
      focusTooltip.css('left', x + 'px')
      focusTooltip.css('top', y + 'px')
      focusTooltip.css('z-index', 9999)
      let attrs = message.split(';')
      let _values
      try {
        let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'labelName'))
        _values = jsonObject.values[attrs[0].split(':')[0]]
      } catch (e) {}
      if (_values == null || _values == undefined || _values == '') _values = attrs[0].split(':')[0]
      if (tipType === 'tip') message = '类型：' + _values
      else message = tipType + _values
      message += '<br>'
      let _d = attrs[0].split(':')[1]
      for (let i = 1; i <= 8; i++) {
        if (attrs[i] && attrs[i] != null && attrs[i] != '' && attrs[i] != 'null') {
          try {
            let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'a' + i + '_' + _d + 'd'))
            let _values = jsonObject.values[attrs[i]]
            if (_values == null || _values == undefined || _values == '') _values = attrs[i]
            message += jsonObject.typeDesc + ': ' + _values + '&nbsp<br>'
          } catch {
            message += attrs[i]
          }
        }
      }
      for (let j = 9; j <= 17; j++) {
        let i = j - 8
        if (attrs[j] && attrs[j] != null && attrs[j] != '' && attrs[j] != 'null') {
          try {
            let jsonObject = JSON.parse(this.selectDictLabel(this.attributeNames, 'b' + i + '_' + _d + 'd'))
            let _values = jsonObject.values[attrs[j]]
            if (_values == null || _values == undefined || _values == '') _values = attrs[j]
            message += jsonObject.typeDesc + ': ' + _values + '&nbsp<br>'
          } catch {
            message += attrs[j]
          }
        }
      }
      if (
        this.selectDictLabel(this.attributeNames, 'show3dSize') &&
        this.selectDictLabel(this.attributeNames, 'show3dSize') === 'true'
      ) {
        message += attrs[attrs.length - 1]
      }
      let headerHtml =
        "<div style='font-size:12px; color: #fec443; font-weight: bold; font-family: MicrosoftYaHei;'>" +
        message +
        '</div>'
      let effectHtml = "<div style='font-size:12px;margin-top:3px;' >" + '</div>'
      this.toolTopbody = headerHtml + effectHtml
      focusTooltip.css('display', 'block')
    },
    ShowAttributesText(show) {
      let opacity = show ? 1 : 0
      for (let m = 0; m < this.mainLayer.length; m++) {
        if (!this.mainLayer[m]) continue
        let items = this.mainLayer[m].getItems()
        for (let i = 0; i < items.length; i++) {
          if (items[i].textObject) {
            items[i].textObject.opacity = opacity
          }
        }
      }
    },
    contextmenuHandler(e) {
      e.preventDefault()
    },
    onWindowResize() {
      this.$refs.pointCloud_rightTopView.onWindowResize()
      this.$refs.pointCloud_leftBottomView.onWindowResize()
      this.$refs.pictureList_leftTopView.onWindowResize()
      this.$refs.pictureList_rightBottomView.onWindowResize()
    },
    animation() {
      if (this.playStarted) {
        if (performance.now() - this.lastPlayTime > 50) {
          this.playFunction()
        }
        requestAnimationFrame(this.animation)
      }
    },
    startPlay() {
      this.playStarted = true
      this.lastPlayTime = performance.now()
      if (this.interval === undefined) {
        this.interval = requestAnimationFrame(this.animation)
      }
    },
    playFunction() {
      if (this.currentIndex < this.fileList.length) {
        if (this.$store.state.markData.playStatus.pic && this.$store.state.markData.playStatus.pcd) {
          this.$store.state.markData.playStatus.pic = false
          this.$store.state.markData.playStatus.pcd = false
          this.saveImage('html2canvas', 'test')
          // let readValue = this.markAnnotations.get("MA:" + this.fileList[this.currentIndex].mQaResultId + "");
          // if(readValue) {
          this.$refs.pointCloud_leftBottomView
            .getPointsCloud(
              this.fileList,
              this.currentIndex,
              this.fileList[this.currentIndex].mQaResultId,
              true,
              this.showAttributesText
            )
            .then(() => {
              this.$store.state.markData.playStatus.pcd = false
              this.$refs.pointCloud_rightTopView
                .getPointsCloud(
                  this.fileList,
                  this.currentIndex,
                  this.fileList[this.currentIndex].mQaResultId,
                  true,
                  this.showAttributesText,
                  'Bumper'
                )
                .then(() => {
                  let query = {
                    taskId: this.queryParams.taskId,
                    mQaResultId: this.fileList[this.currentIndex].mQaResultId,
                  }
                  this.$router.replace({
                    path: '/mark/RadarView',
                    query: query,
                  })
                  if (this.imgCount > 0) {
                    this.$refs.pictureList_leftTopView.loadDrawing(
                      this.currentIndex,
                      this.fileList[this.currentIndex].mQaResultId,
                      this.showAttributesText
                    )
                    this.$refs.pictureList_rightBottomView.loadDrawing(
                      this.currentIndex,
                      this.fileList[this.currentIndex].mQaResultId,
                      this.showAttributesText
                    )
                  }
                  if (this.currentIndex < this.fileList.length) this.currentIndex++
                  this.lastPlayTime = performance.now()
                })
            })
          // }
        }
      } else {
        this.saveImage('html2canvas', 'test')
        this.encoder.compile(false, (output) => {
          const url = (window.webkitURL || window.URL).createObjectURL(output)
          let a = document.createElement('a')
          a.style.display = 'none'
          a.setAttribute('href', url)
          a.setAttribute('download', this.taskName + '_w.mp4')
          document.body.appendChild(a)
          a.click()
          URL.revokeObjectURL(blob)
          document.body.removeChild(a)
        })
        this.playStarted = false
        this.currentIndex = this.fileList.length - 1
        cancelAnimationFrame(this.interval)
        this.interval = undefined
      }
    },
    pausePlay() {
      this.playStarted = false
      cancelAnimationFrame(this.interval)
      this.interval = undefined
      this.changePage(0)
    },
    saveChange() {
      this.msgSuccess('save success.')
      let changeStore = this.changeList.fetch()
      for (let key in changeStore) {
        let tmp = changeStore[key]
        if (tmp.action && tmp.action === 'update') {
          if (tmp.type === 'path' && tmp.info.mMarkAnnotationId && tmp.info.markType === 'rect') {
            let path = tmp.info
            let x = '',
              y = ''
            let tmpPoint = path.pointToLocal(path.point1.segments[0].point)
            x += tmpPoint.x + ';'
            y += tmpPoint.y + ';'
            tmpPoint = path.pointToLocal(path.point3.segments[0].point)
            x += tmpPoint.x + ';'
            y += tmpPoint.y + ';'
            if (path.midPath) {
              tmpPoint = path.pointToLocal(path.midPath.segments[0].point)
              x += tmpPoint.x + ';'
              y += tmpPoint.y + ';'
            }
            if (path.rangePath) {
              tmpPoint = path.pointToLocal(path.rangePath.segments[0].point)
              x += tmpPoint.x + ';'
              y += tmpPoint.y + ';'
              tmpPoint = path.pointToLocal(path.rangePath.segments[1].point)
              x += tmpPoint.x + ';'
              y += tmpPoint.y + ';'
            }
            let params = {
              mMarkAnnotationId: path.mMarkAnnotationId,
              x: x.slice(0, x.length - 1),
              y: y.slice(0, y.length - 1),
            }
            updateAnnotation(params)
          } else if (
            tmp.type === 'path' &&
            tmp.info.mMarkAnnotationId &&
            (tmp.info.markType === 'poly' || tmp.info.markType === 'line')
          ) {
            let path = tmp.info
            let x = '',
              y = ''
            for (let i = 0; i < path.segments.length; i++) {
              let tmpPoint = path.pointToLocal(path.segments[i].point)
              x += tmpPoint.x + ';'
              y += tmpPoint.y + ';'
            }
            let params = {
              mMarkAnnotationId: path.mMarkAnnotationId,
              x: x.slice(0, x.length - 1),
              y: y.slice(0, y.length - 1),
            }
            updateAnnotation(params)
          }
        } else if (tmp.action && tmp.action === 'delete') {
          let params = {
            mMarkAnnotationId: tmp.info.mMarkAnnotationId,
          }
          deleteAnnotation(params)
        }
        this.changeList.remove(key)
      }
      this.changeList.clear()
      this.removeCache(this.fileList[this.currentIndex].mQaResultId)
      this.changePage(0)
    },
    submitUpdateForm() {
      if (!this.form.mMarkAnnotationId) {
        alert('系统未知错误!')
        return
      }
      updateAnnotationAttributes(this.form).then((response) => {
        if (response.code === 200) {
          this.msgSuccess('修改成功')
          this.removeCache(this.form.mQaResultId)
          this.changePage(0)
          this.cancelUpdateForm()
        } else {
          this.msgError(response.msg)
        }
      })
    },
    cancelUpdateForm() {
      this.attributesUpdateDialogOpen = false
      this.form = {
        mMarkAnnotationId: undefined,
        name: undefined,
        a1: undefined,
        a2: undefined,
        a3: undefined,
        a4: undefined,
        a5: undefined,
        a6: undefined,
        a7: undefined,
        a8: undefined,
      }
      this.resetForm('form')
    },
    //图片格式转换方法
    dataURLToBlob(dataurl) {
      let arr = dataurl.split(',')
      let mime = arr[0].match(/:(.*?);/)[1]
      let bstr = atob(arr[1])
      let n = bstr.length
      let u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new Blob([u8arr], { type: mime })
    },
    //点击方法
    saveImage(divText, imgText) {
      let canvasID = this.$refs[divText]
      let that = this
      // let a = document.createElement('a');
      html2canvas(canvasID).then((canvas) => {
        this.encoder.add(canvas)
        console.log('this.encoder', this.encoder)
        let dom = document.body.appendChild(canvas)
        dom.style.display = 'none'
        // a.style.display = 'none';
        document.body.removeChild(dom)
        let blob = that.dataURLToBlob(dom.toDataURL('image/png'))
        let url = URL.createObjectURL(blob)
        // a.setAttribute('href', URL.createObjectURL(blob));
        // //这块是保存图片操作  可以设置保存的图片的信息
        // a.setAttribute('download', imgText + '.png');
        // document.body.appendChild(a);
        // a.click();
        // URL.revokeObjectURL(blob);
        // document.body.removeChild(a);
      })
    },
  },
  // 捕获界面刷新事件，清除标注结果缓存
  beforeRouteEnter(to, from, next) {
    next((vm) => {
      if (from.name === null) {
        vm.removeAnnotationCache('MA:' + to.query.mQaResultId)
      }
    })
  },
  created() {
    this.encoder = new window.Whammy.Video(500)
    if (!this.$route.query.taskId || !this.$route.query.mQaResultId) this.$router.go(-1)
    this.queryParams.taskId = this.$route.query.taskId
    this.queryParams.mQaResultId = this.$route.query.mQaResultId
    this.selectedObjectA1 = this.$route.query.selectedObjectA1
    window.addEventListener('contextmenu', this.contextmenuHandler, false)
    this.$store.dispatch('app/closeSideBar', { withoutAnimation: true })
    this.getDicts('mark_result_error_type').then((response) => {
      this.errorTypeOptions = response.data
    })

    //在页面刷新时将paperToolPosition的信息保存到store里，再由全局main.js保存到localStorage里
    window.addEventListener('beforeunload', () => {
      localStorage.setItem('currentIndex', this.currentIndex)
    })
  },
  mounted() {
    this.qaTaskQuery()
    window.addEventListener('resize', this.onWindowResize, false)
    document.addEventListener('keydown', this.keyDownHandler, false)
    screenfull.on('change', (event) => {
      this.isFullscreen = screenfull.isFullscreen
    })
  },
  destroyed() {
    this.cacheStatus = {
      taskId: null,
      cacheIndex: 0,
    }
    cancelAnimationFrame(this.animationFrameId)
    window.removeEventListener('contextmenu', this.contextmenuHandler, false)
    window.removeEventListener('resize', this.onWindowResize, false)
    document.removeEventListener('keydown', this.keyDownHandler, false)
  },
}
</script>
<style lang="scss" scoped>
html,
body {
  width: 100%;
  height: 100%;
}

/* Scale canvas with resize attribute to full size */
canvas[resize] {
  width: 100%;
  height: auto;
}

.special_focus_toolTip {
  z-index: 7;
  position: absolute;
  display: none;
  width: 180px;
  height: 240px;
  border-style: solid;
  transition: left 0.4s cubic-bezier(0.23, 1, 0.32, 1), top 0.4s cubic-bezier(0.23, 1, 0.32, 1);
  background-color: rgba(50, 50, 50, 0.701961);
  border-width: 0px;
  border-color: #333333;
  border-radius: 4px;
  color: #ffffff;
  font-style: normal;
  font-variant: normal;
  font-weight: normal;
  font-stretch: normal;
  font-size: 14px;
  font-family: 'Microsoft YaHei';
  line-height: 21px;
  padding: 10px 10px;
  pointer-events: none;
}

.icon-list {
  height: calc(100vh - 155px);
  overflow-y: auto;
  .color-name {
    height: 30px;
    line-height: 30px;
    // margin-bottom: -5px;
    cursor: pointer;
    width: 50%;
    float: left;
    span {
      vertical-align: 0.3em;
      fill: currentColor;
      margin-left: 5px;
    }
  }
}
.bottom-div {
  bottom: 0;
  height: 46px;
  line-height: 46px;
  padding: 0 10px;
  background: #fff;
  .el-form-item {
    margin: 0;
    display: inline-grid;
    vertical-align: middle;
  }
  .filename {
    word-wrap: break-word;
    word-break: break-all;
    display: flex;
    align-items: center;
    height: 46px;
    span {
      line-height: 18px;
    }
  }
  .color-name-btn {
    display: flex;
    align-items: center;
    height: 46px;
    margin-left: 15px;
  }
}
</style>
